import { acceptHMRUpdate, defineStore } from 'pinia';
import ls from '@/utils/local-storage';
import { STORAGE_TOKEN_KEY } from './app';
import type { LoginParams, Role, UserInfo, LoginResp } from '@/api/user/login';
import { postLogout, getCurrentUser, postAccountLogin } from '@/api/user/login';
import type { RouteRecordRaw } from 'vue-router';
import { filterChildRoute, hasAuthority } from '@/utils/authority';
import { filterMenu } from '@/utils/menu-util';
import { default as router, routes } from '@/router';
import type { MenuDataItem } from '@/router/typing';
import { generatorDynamicRouter } from '@/router/generator-routers';
import type { ResponseData } from '@/api/typing';
import { localStorage } from '@/utils/local-storage';
import { isArray, isObject } from 'lodash-es';

export interface UserState {
    token?: string;
    nickname: string;
    avatar: string;
    role?: Role;
    orderPage?: number;
    allowRouters: RouteRecordRaw[];
    permissions: string[];
    extra: {
        [key: string]: any;
    };
    [key: string]: any;
}

export const LOGIN = 'LOGIN';
export const LOGOUT = 'LOGOUT';
export const GET_INFO = 'GET_INFO';
export const GENERATE_ROUTES = 'GENERATE_ROUTES';
export const GENERATE_ROUTES_DYNAMIC = 'GENERATE_ROUTES_DYNAMIC';

export const SET_TOKEN = 'SET_TOKEN';
export const SET_AVATAR = 'SET_AVATAR';
export const SET_ROLE = 'SET_ROLE';
export const SET_INFO = 'SET_INFO';
export const SET_ROUTERS = 'SET_ROUTERS';
export const RESET_CURRENT_USER = 'RESET_CURRENT_USER';

export const initState = (): UserState => ({
    token: '',
    username: '',
    nickname: '',
    phone: '',
    avatar: '',
    orderPage: 0,
    extra: {},
    role: undefined,
    allowRouters: [],
    permissions: [],
    menus: [],
});

export const useUserStore = defineStore('user', {
    state: initState,
    getters: {
        info: state => state.extra,
        currentUser: state => state,
    },
    actions: {
        [SET_TOKEN](tokenInfo: LoginResp) {
            if (isObject(tokenInfo)) {
                this.token = tokenInfo.accessToken;
                ls.set(STORAGE_TOKEN_KEY, this.token);
            } else {
                this.token = null;
                ls.set(STORAGE_TOKEN_KEY, null);
            }
            // ls.set('STORAGE_USER_ID', tokenInfo.userinfo.id);
        },
        [SET_INFO](info: any) {
            if (info.roles) {
                this.role = info.roles;
            }
            if (info.menus) {
                this.menus = info.menus;
            }
            if (info.user.id) {
                this.userId = info.user.id;
                this.nickname = info.user.nickname;
                this.phone = info.user.phone;
            }
            if (isArray(info.permissions)) {
                this.permissions = info.permissions;
            }
            this.extra = { ...info };
        },
        [SET_ROLE](role: UserState['role']) {
            this.role = role;
        },
        [SET_AVATAR](avatar: UserState['avatar']) {
            this.avatar = avatar;
        },
        [SET_ROUTERS](allowRoutes: UserState['allowRouters']) {
            this.allowRouters = allowRoutes;
        },
        [RESET_CURRENT_USER]() {
            this.$reset();
        },

        async [LOGIN](info: LoginParams) {
            return new Promise((resolve, reject) => {
                // call ajax
                const fd = new FormData();
                fd.append('grant_type', 'password');
                Object.keys(info).forEach(key => {
                    fd.append(key, info[key]);
                });
                postAccountLogin(fd)
                    .then(res => {
                        this.SET_TOKEN(res.data);
                        resolve(res.data);
                    })
                    .catch(error => {
                        reject(error);
                    });
            });
        },
        async [GET_INFO](): Promise<UserInfo> {
            return new Promise(async (resolve, reject) => {
                const userId = ls.get('STORAGE_USER_ID');

                getCurrentUser(userId)
                    .then((res: ResponseData<UserInfo>) => {
                        this.SET_INFO(res.data);
                        resolve(res.data);
                    })
                    .catch(err => {
                        // 获取登录用户信息后，直接清理掉当前 token 并强制让流程走到登录页
                        this.SET_TOKEN(null);
                        reject(err);
                    });
            });
        },
        // // 从路由表构建路由（前端对比后端权限字段过滤静态路由表）
        // async [GENERATE_ROUTES](info: UserInfo) {
        //     return new Promise<RouteRecordRaw[]>(resolve => {
        //         // 修改这里可以进行接口返回的对象结构进行改变
        //         // 亦或是去掉 info.role 使用别的属性替代
        //         // 任何方案都可以，只需要将最后拼接构建好的路由数组使用
        //         // router.addRoute() 添加到当前运行时的路由中即可
        //         const { permissions } = (info.role || {}) as Role;
        //         const allRoutes = filterMenu(routes);
        //         const permissionsKey = permissions?.map(permission => permission.name);
        //         const allowRoutes = !permissionsKey
        //             ? allRoutes
        //             : allRoutes.filter(route => {
        //                   // parnent route filter
        //                   const hasAllow = hasAuthority(route as MenuDataItem, permissionsKey!);
        //                   if (hasAllow && route.children && route.children.length > 0) {
        //                       // current route children filter
        //                       route.children = filterChildRoute(route as MenuDataItem, permissionsKey!);
        //                   }
        //                   return hasAllow;
        //               });
        //         console.log('allowRoutes', allowRoutes);
        //         // 添加到路由表
        //         const {
        //             // eslint-disable-next-line
        //             children: _,
        //             ...mainRoute
        //         } = routes[0];
        //         const route = {
        //             ...mainRoute,
        //             children: allowRoutes,
        //         };
        //         router.addRoute(route as RouteRecordRaw);
        //         this.SET_ROUTERS(allowRoutes as RouteRecordRaw[]);
        //         resolve(allowRoutes as RouteRecordRaw[]);
        //     });
        // },
        // 从后端获取路由表结构体，并构建前端路由
        async [GENERATE_ROUTES_DYNAMIC]() {
            return new Promise((resolve, reject) => {
                generatorDynamicRouter()
                    .then((response: any) => {
                        console.log(response, 'response GENERATE_ROUTES_DYNAMIC');
                        const { rootRouter: routes, user, roles, permissions, orderPage, menus } = response;
                        this.SET_INFO({
                            user,
                            roles,
                            permissions,
                            orderPage,
                            menus,
                        });

                        const allowRoutes = routes.children || [];

                        // 添加到路由表
                        router.addRoute(routes as RouteRecordRaw);
                        this.SET_ROUTERS(allowRoutes);
                        console.log('routes', routes);

                        resolve(routes);
                    })
                    .catch(err => {
                        console.error('generatorDynamicRouter', err);
                        this.SET_TOKEN(null);
                        reject(err);
                    });
            });
        },
        async [LOGOUT]() {
            return new Promise<void>(resolve => {
                const fd = new FormData();
                const savedToken = localStorage.get(STORAGE_TOKEN_KEY);
                localStorage.set('menuCacheList', null);
                fd.append('token', `${savedToken}`);
                postLogout(fd).finally(() => {
                    this.SET_TOKEN(null);
                    resolve();
                });
            });
        },
    },
});

const hot = import.meta.webpackHot || (import.meta as any).hot;
if (hot) {
    hot.accept(acceptHMRUpdate(useUserStore, hot));
}
